import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:hixing_app/const/gaps.dart';

enum PanDirection {
  up,
  down,
  left,
  right,
}

class OperateScrollNotifier extends ChangeNotifier {
  double _scrollX = 0;
  double _scrollY = 0;

  double get scrollX => _scrollX;

  double get scrollY => _scrollY;

  updateScrollX(double scroll) {
    _scrollX = scroll;
    notifyListeners();
  }

  updateScrollY(double scroll) {
    _scrollY = scroll;
    notifyListeners();
  }
}

class OperatingPainterPage extends StatefulWidget {
  const OperatingPainterPage({super.key});

  @override
  OperatingPainterPageState createState() => OperatingPainterPageState();
}

class OperatingPainterPageState extends State<OperatingPainterPage>
    with SingleTickerProviderStateMixin {
  OperateScrollNotifier operateScrollNotifier = OperateScrollNotifier();

  PanDirection panDirection = PanDirection.left;
  Offset startPoint = Offset.zero;
  Offset lastOffset = Offset.zero;
  Offset moveOffset = Offset.zero;
  Offset animateOffset = const Offset(200, 0);
  double oldScrollX = 0;
  bool isScale = false;

  /// 定义动画的容差，用来更好的决定动画何时被认为是完成的。这对于精细控制动画的终止条件非常有用，尤其是在物理仿真中
  late final Tolerance _kDefaultTolerance = Tolerance(
    velocity: 1.0 / (0.050 * View.of(context).devicePixelRatio),
    // logical pixels per second
    distance: 1.0 / View.of(context).devicePixelRatio, // logical pixels
  );

  /// 创建一个没有边界的控制器
  late AnimationController animationCtrl =
      AnimationController.unbounded(vsync: this)..addListener(onAnimated);

  void onAnimated() {
    // print(animationCtrl.value);
    double dx = animationCtrl.value - oldScrollX;
    operateScrollNotifier.updateScrollX(
        oldScrollX + (panDirection == PanDirection.left ? -dx : dx));
  }

  void _startAnim({required velocity}) async {
    /// 定义 滚动 clamping simulation
    final Simulation simulation = ClampingScrollSimulation(
      /// 初始位置
      position: operateScrollNotifier.scrollX,

      /// 初始速度
      velocity: velocity,

      /// 摩擦力
      friction: 0.015,
      tolerance: _kDefaultTolerance,
    );
    await animationCtrl.animateWith(simulation);
  }

  @override
  void initState() {
    super.initState();
    animationCtrl.addListener(onAnimated);
  }

  @override
  void dispose() {
    animationCtrl.removeListener(onAnimated);
    animationCtrl.dispose();
    operateScrollNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('板子底部'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16),
            child: Row(
              children: [
                Icon(
                  Icons.warning,
                  color: Colors.orangeAccent,
                ),
                Gaps.hGap10,
                Text("未连接设备"),
                const Spacer(),
                Icon(
                  Icons.settings,
                  color: Colors.black38,
                ),
              ],
            ),
          ),
          Expanded(
              child: Stack(
            children: [
              RepaintBoundary(
                  child: GestureDetector(
                onScaleStart: (details) {
                  // print("双指操作开始：${details.pointerCount}");
                  if (details.pointerCount == 1) {
                    animationCtrl.stop();
                    isScale = true;
                    startPoint = details.focalPoint;
                    lastOffset = Offset(operateScrollNotifier.scrollX, 0);
                  }
                },
                onScaleUpdate: (details) {
                  print(details.pointerCount == 1);
                  if (details.pointerCount == 1) {
                    // print(
                    //     "双指操作移动中：${details.pointerCount}，偏移量：${details.focalPoint}");
                    moveOffset = details.focalPoint;
                    Offset current = (startPoint - details.focalPoint);
                    print("${current.dx}=====current ");
                    operateScrollNotifier
                        .updateScrollX(lastOffset.dx + current.dx);
                  }
                },
                onScaleEnd: (details) {
                  if (isScale) {
                    isScale = false;

                    /// pixelsPerSecond : 手势停止的速度，可以做 fliting
                    // print("双指操作结束====== ${lastOffset}");

                    final Offset velocity = details.velocity.pixelsPerSecond;
                    final double magnitude = velocity.distance;
                    oldScrollX = operateScrollNotifier.scrollX;
                    // print("当前的速度值：${magnitude}");
                    if (magnitude > 0) {
                      if ((startPoint - moveOffset).dx > 0) {
                        // print("向右滑");
                        panDirection = PanDirection.right;
                      } else {
                        // print("向左滑");
                        panDirection = PanDirection.left;
                      }
                      // animateOffset =  Offset(magnitude * 0.4, 0);
                      _startAnim(velocity: magnitude);
                    }
                  }
                },
                child: CustomPaint(
                  size: Size(double.infinity, double.infinity),
                  painter: OperatingPainter(
                    operateScrollNotifier: operateScrollNotifier,
                  ),
                ),
              )),
              Positioned(
                left: 0,
                top: 110,
                child: IconButton(
                  onPressed: () {
                    operateScrollNotifier
                        .updateScrollX(operateScrollNotifier.scrollX - 10);
                  },
                  icon: Icon(
                    Icons.arrow_left,
                    size: 100,
                  ),
                ),
              ),
              Positioned(
                right: 0,
                top: 110,
                child: IconButton(
                  onPressed: () {
                    operateScrollNotifier
                        .updateScrollX(operateScrollNotifier.scrollX + 10);
                  },
                  icon: Icon(
                    Icons.arrow_right,
                    size: 100,
                  ),
                ),
              ),
              Positioned(
                top: 220,
                left: 120,
                child: IconButton(
                  onPressed: () {
                    operateScrollNotifier
                        .updateScrollY(operateScrollNotifier.scrollY + 10);
                  },
                  icon: Icon(
                    Icons.arrow_downward,
                    size: 100,
                  ),
                ),
              ),
              Positioned(
                top: 20,
                left: 120,
                child: IconButton(
                  onPressed: () {
                    operateScrollNotifier
                        .updateScrollY(operateScrollNotifier.scrollY - 10);
                  },
                  icon: Icon(
                    Icons.arrow_upward,
                    size: 100,
                  ),
                ),
              ),
            ],
          ))
        ],
      ),
    );
  }
}

class OperatingPainter extends CustomPainter {
  OperatingPainter({required this.operateScrollNotifier})
      : super(repaint: operateScrollNotifier);

  /// 格子间隔
  final double gap = 10;

  /// 刻度间隔
  final double padding = 30;

  /// 粗颜色
  final Color boldColor = Colors.black45;

  /// 细颜色
  final Color thinColor = Color(0xFF999999).withOpacity(0.4);
  final Color intColor = Color(0xFF999999).withOpacity(0.7);

  final OperateScrollNotifier operateScrollNotifier;

  @override
  void paint(Canvas canvas, Size size) {
    double width = size.width;
    double height = size.height;

    Paint paint = Paint()
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;

    /// 绘制 线条 绘制横向线条
    canvas.drawLine(const Offset(0.0, 0.0), Offset(size.width, 0.0),
        paint..color = thinColor);
    canvas.drawLine(const Offset(0.0, 0.0), Offset(0.0, size.height),
        paint..color = thinColor);

    canvas.drawLine(Offset(0.0, padding), Offset(size.width, padding),
        paint..color = boldColor);
    canvas.drawLine(Offset(padding, 0.0), Offset(padding, size.height),
        paint..color = boldColor);
    canvas.translate(padding, padding);
    int yLine = (height / gap).ceil();
    int xLine = (width / gap).ceil();

    _drawYLine(
      canvas: canvas,
      paint: paint,
      line: yLine,
      size: size,
    );

    _drawXLine(
      canvas: canvas,
      paint: paint,
      line: xLine,
      size: size,
    );
  }

  void _drawYLine({
    required int line,
    required Size size,
    required Paint paint,
    required Canvas canvas,
  }) {
    canvas.save();
    double scrollY = operateScrollNotifier.scrollY;
    int step = 0;
    canvas.translate(0, scrollY);
    step = ((scrollY / gap).ceil());
    print(step);
    double renderLine = line.toDouble() + step.abs();
    canvas.clipRect(Offset(-padding, -scrollY) & Size(size.width, size.height));
    _drawYLineLoop(
        renderLine: renderLine,
        paint: paint,
        textOffset: Offset(4.0, -18),
        canvas: canvas,
        size: size,
        gap: gap);
    if (step > 0) {
      canvas.save();
      canvas.translate(0.0, -renderLine * gap);
      // canvas.drawLine(
      //     Offset(0.0, -0), Offset(0.0, size.height), paint..color = Colors.red);
      _drawYLineLoop(
          renderLine: step,
          paint: paint,
          canvas: canvas,
          size: size,
          hideFirst: true,
          textOffset: Offset(-18, -18),
          textPrefix: "-",
          gap: -gap);
      // print("绘制负数");
      canvas.restore();
    }
    canvas.restore();
  }

  void _drawYLineLoop(
      {required renderLine,
      required Paint paint,
      required Canvas canvas,
      required Size size,
      bool hideFirst = false,
      required Offset textOffset,
      String textPrefix = "",
      required double gap}) {
    for (int i = 0; i < renderLine; i++) {
      bool isHideFirst = hideFirst && i == 0;
      bool isTen = i % gap == 0;
      bool isFive = i % 5 == 0;
      paint.color = isHideFirst
          ? Colors.transparent
          : isTen
              ? intColor
              : thinColor;
      canvas.drawLine(
          Offset(
              isTen
                  ? -padding
                  : isFive
                      ? -16
                      : -8,
              0.0),
          Offset(size.width, 0.0),
          paint);
      canvas.translate(0.0, gap);
      if (isTen) {
        if (!isHideFirst) {
          drawText(
              canvas: canvas,
              paint: paint,
              textAlign: TextAlign.end,
              color: intColor,
              axis: Axis.vertical,
              textOffset: textOffset,
              fontSize: 12,
              text: "${i * 1} ${textPrefix}");
        }
      }
    }
  }

  /// 绘制无限网格的核心逻辑（优化版本）
  /// 1，计算出总的长度
  /// 2，计算出需要跳过的长度
  /// 3，计算出当前屏幕需要绘制的长度
  /// 绘制 ：
  /// 1，首先需要绘制全部的网格线条
  /// 2，计算出 需要跳过的initStep
  /// 比如当前需要绘制1-100网格，但是屏幕只需要绘制 90-100，
  /// 所以initStep = 90，step = 100，这样就可以绘制当前屏幕所需要的网格
  /// 然后计算出需要跳过的网格线 在drawLine之前用canvas.translate偏移到initStep位置开始绘制
  ///  canvas.translate(initStep * gap, 0.0);
  void _drawXLine({
    required int line,
    required Size size,
    required Paint paint,
    required Canvas canvas,
  }) {
    canvas.save();
    double scrollX = operateScrollNotifier.scrollX;
    double viewportWidth = size.width;

    /// 正向视口宽度
    double positivePort = 0.0;

    /// 反向视口宽度
    double reversePort = 0.0;

    /// 计算正反向视口尺寸
    if (scrollX >= 0) {
      positivePort = viewportWidth;
      reversePort = 0.0;
    } else {
      double computedW = viewportWidth - scrollX.abs();
      positivePort = computedW < 0 ? 0 : computedW;
      reversePort = viewportWidth - positivePort;
    }

    /// 绘制正向纵向网格
    if (positivePort > 0) {
      canvas.save();
      canvas.translate(-scrollX, 0);
      int step = (positivePort / gap).floor();

      /// 两个值取最大的，若 (scrollX / gap).ceil()比0小，则取0,这里判断最小值0是为了解决scrollX是负数的情况
      int initStep = math.max(0, (scrollX / gap).ceil());
      _drawXLineLoop(
          step: step + initStep,

          /// 在哪个step开始绘制
          initStep: initStep,
          paint: paint,
          textOffset: Offset(4.0, -18),
          canvas: canvas,
          size: size,
          gap: gap);
      canvas.restore();
    }
    if (reversePort > 0) {
      /// 绘制反向纵向网格
      canvas.save();
      canvas.translate(-scrollX, 0);
      canvas.drawLine(Offset(0.0, -0.0), Offset(0.0, size.height),
          paint..color = Colors.red);

      /// 总的格子步数
      int reverseStep = ((scrollX / gap).floor().abs());
      //
      /// 两个值取最大的，若 (scrollX / gap).ceil()比0小，则取0
      /// 当正向视口大于0的时候，reverseInitStep取0，当小于0的时候，
      ///把总的长度，减去当前屏幕的长度，除以gap，就是需要跳过的网线步数长度
      int reverseInitStep = ((scrollX.abs() - reversePort) / gap).ceil();

      _drawXLineLoop(
          step: reverseStep,
          initStep: reverseInitStep,
          paint: paint,
          canvas: canvas,
          size: size,
          hideFirst: true,
          reverse: true,
          textOffset: Offset(26, -18),
          // reverseGap: viewportWidth,
          textPrefix: "-",
          gap: gap);
      canvas.restore();
      print(
          "reverseInitStep：${reverseInitStep},当前滚动x：${scrollX},正向视口尺寸：${positivePort}");
    }

    canvas.restore();
  }

  void _drawXLineLoop(
      {required int step,
      required int initStep,
      required Paint paint,
      required Canvas canvas,
      required Size size,
      double reverseGap = 0,
      bool hideFirst = false,
      bool reverse = false,
      required Offset textOffset,
      String textPrefix = "",
      required double gap}) {
    if (reverse) {
      canvas.translate(-(initStep * gap), 0.0);
    } else {
      canvas.translate(initStep * gap, 0.0);
    }
    for (int i = initStep; i < step; i++) {
      bool isTen = i % gap == 0;
      bool isFive = i % 5 == 0;
      bool isHideFirst = hideFirst && i == 0;
      paint.color = isHideFirst
          ? Colors.transparent
          : isTen
              ? intColor
              : thinColor;

      canvas.drawLine(
          Offset(
              0.0,
              isTen
                  ? -padding
                  : isFive
                      ? -16
                      : -8),
          Offset(0.0, size.height),
          paint);

      canvas.translate(reverse ? -gap : gap, 0.0);
      if (isTen) {
        if (!isHideFirst) {
          drawText(
              canvas: canvas,
              paint: paint,
              textAlign: TextAlign.end,
              color: intColor,
              axis: Axis.horizontal,
              textOffset: textOffset,
              fontSize: 12,
              text: " ${i * 1}${textPrefix}");
        }
      }
    }
  }

  void drawText(
      {required Canvas canvas,
      required TextAlign textAlign,
      required Paint paint,
      Axis axis = Axis.horizontal,
      Color? color,
      double fontSize = 14,
      FontWeight fontWeight = FontWeight.normal,
      Offset textOffset = Offset.zero,
      String text = ""}) {
    Paint textPaint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 1;
    TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: text,
        style: TextStyle(
            color: color,
            fontSize: fontSize,
            fontWeight: FontWeight.normal,
            foreground: color == null ? textPaint : null),
      ),
      textDirection: TextDirection.rtl,
    );
    textPainter.layout(); // 进行布局
    //获取size需要在layout之后
    Size textSize = textPainter.size;
    if (axis == Axis.vertical) {
      canvas.save();
      // canvas.translate(textSize.width, textSize.height);
      canvas.rotate(-math.pi * 0.5);
      // canvas.translate(-textSize.width, -textSize.height);
    }

    if (axis == Axis.horizontal) {
      /// 横轴文本
      textPainter.paint(canvas, Offset.zero - Offset(gap, gap) + textOffset);
    } else {
      /// 纵轴文本
      textPainter.paint(canvas, Offset(26, 0) - Offset(gap, gap) + textOffset);
    }
    if (axis == Axis.vertical) {
      canvas.restore();
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}
